跳到主要内容

Vue3 的生命周期

Vue2 的生命周期

Nonuz6.png

Vue3 的变更

Vue3 进行了以下变更

  • beforeCreate -> setup()
  • created -> setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

几个需要注意的点

  • 在 Vue3.x 中,为了兼容 Vue2.x 的语法,所有旧的生命周期函数得到保留(除了 beforeDestroydestroyed
  • 当生命周期混合使用时:Vue3.x 的生命周期相对优先于 Vue2.x 的执行(比如:onMountedmounted 先执行)
  • 这个 setup 执行时间位于 beforeCreatecreated 之间,所以无法使用 datamethods(因为这两个都还没有初始化好)
  • 因为无法使用 datamethods 所以 Vue3 为了避免我们错误的使用,它将 this 修改成了 undefined
  • setup 函数只能是同步的,不能是异步的(就是不能在前面加 async

Vue3 的生命周期钩子

在Composition API中,我们需要先导入对应的生命周期钩子才能使用它。这么做,是为了让我们的项目尽可能的轻量化。

import { onMounted } from 'vue'

使用这些生命周期也和之前用法不太一样,现在都是在 setup 里面导入使用

import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onActivated, onDeactivated, onErrorCaptured } from 'vue'

export default {
setup() {
onBeforeMount(() => {
// ...
})
onMounted(() => {
// ...
})
onBeforeUpdate(() => {
// ...
})
onUpdated(() => {
// ...
})
onBeforeUnmount(() => {
// ...
})
onUnmounted(() => {
// ...
})
onActivated(() => {
// ...
})
onDeactivated(() => {
// ...
})
onErrorCaptured(() => {
// ...
})
}
}

各个方法执行的时机

onBeforeMount——挂载开始前调用 onMount——挂载后调用 onBeforeUpdate——当响应数据改变,且重新渲染前调用 onUpdated——重新渲染后调用 onBeforeUnmount——Vue实例销毁前调用 onUnmounted——实例销毁后调用 onActivated——当keep-alive组件被激活时调用 onDeactivated——当keep-alive组件取消激活时调用 onErrorCaptured——从子组件中捕获错误时调用

Update 钩子

无论何时响应数据被修改,updated 生命周期事件都将触发,并且触发渲染更新。

beforeUpdate() and onBeforeUpdate()

在数据修改且组件重渲染之前执行。这是任何更改还未发生前,手动修改 DOM 的好地方。beforeUpdate 对追踪组件的编辑次数时非常有用,甚至可以通过追踪对应的操作来创建一个 “撤销” 功能。

updated() and onUpdated()

updated 方法在 DOM 更新后调用一次。

onUpdated 方法会在组件更新后调用,只有 data 里的变量改变并且要在页面重新渲染完成之后,才会进 updated 生命周期,只改变 data 里的值但是没有再页面上渲染该值的话并不会触发 updated 方法。

这是一段 beforeUpdate 和 updated 的基本代码

<template>
<div>
<p>{{val}} | edited {{ count }} times</p>
<button @click='val = Math.random(0, 100)'>Click to Change</button>
</div>
</template>

相对应的 script 代码

import { ref, onBeforeUpdate, onUpdated } from 'vue'

export default {
setup () {
const count = ref(0)
const val = ref(0)

onBeforeUpdate(() => {
count.value++;
console.log("beforeUpdate");
})

onUpdated(() => {
console.log("updated() val: " + val.value)
})

return {
count, val
}
}
}

这些方法很有用,但多数情况我们可能会通过监听器(watchers)去检测对应数据的改变。因为监听器可以很好的提供数据更改时的旧值和新值。

另一种方式是通过计算属性来改变元素的状态。

Destruction钩子(清理)

destruction 钩子在组件被移除并需要清理一些待释放的功能时使用。这是删除事件监听并且防止内存溢出的好地方。

beforeUnmount() and onBeforeUnmounted()

触发在组件开始销毁之前,在此会进行绝大多数的清理工作。在此阶段,你的组件仍然拥有所有的功能,任何东西都还未被销毁。

举一个删除事件监听的例子

 import { onMounted, onBeforeUnmount } from 'vue' 

export default {
setup () {

const someMethod = () => {
// do smth
}

onMounted(() => {
console.log('mount')
window.addEventListener('resize', someMethod);
})

onBeforeUnmount(() => {
console.log('unmount')
window.removeEventListener('resize', someMethod);
})

}
}

unmounted() and onUnmounted()

此时,大多数组件和它的属性已经销毁,所以你能做的不多。同样,我打印一段数据去确切观察发生了什么。

import { onUnmounted } from 'vue'

export default {
setup () { /* Composition API */

onUnmounted(() => {
console.log('unmounted')
})

},
unmounted() { /* Options API */
console.log('unmounted')
}
}

Activation 钩子(管理Keep-Alive组件)

keep-alive 标签是对动态组件的包装元素。它保存一段组件实例的缓存引用,如此 Vue 就不需要在每次动态组件(dynamic component)改变时创建一个新的实例。

对于这种特殊的使用情况,Vue提供了两个生命周期钩子。

activated() and onActivated()

无论何时动态组件被 “重新激活”(意味着此时是动态组件激活视图)时该钩子方法都将被调用。

举个例子,如果我们使用 keep-alive 管理不同的 tab 视图,每次我们切换tab时,当前的tab将会触发activated钩子。

假设我们有以下用 keep-alive 包装的 动态组件 setup。

<template>
<div>
<span @click='tabName = "Tab1"'>Tab 1 </span>
<span @click='tabName = "Tab2"'>Tab 2</span>
<keep-alive>
<component :is='tabName' class='tab-area'/>
</keep-alive>
</div>
</template>

<script>
import Tab1 from './Tab1.vue'
import Tab2 from './Tab2.vue'

import { ref } from 'vue'

export default {
components: {
Tab1,
Tab2
},
setup () { /* Composition API */
const tabName = ref('Tab1')

return {
tabName
}
}
}
</script>

在我们的 Tab1.vue 组件中,我们能够如下访问 activation 钩子。

<template>
<div>
<h2>Tab 1</h2>
<input type='text' placeholder='this content will persist!'/>
</div>
</template>

<script>
import { onActivated } from 'vue'

export default {
setup() {
onActivated(() => {
console.log('Tab 1 Activated')
})
}
}
</script>

deactivated() and onDeactivated()

和你想象的一样,视图不在动态组件中继续保持激活时触发此钩子。

该钩子在某些情况下非常有用,例如特定视图失去焦点时,保存用户数据和触发动画。

我们能够如下所示,捕获该生命周期钩子

import { onActivated, onDeactivated } from 'vue'

export default {
setup() {
onActivated(() => {
console.log('Tab 1 Activated')
})

onDeactivated(() => {
console.log('Tab 1 Deactivated')
})
}
}

现在,当我们切换 tab 时,每个动态组件的状态都将被保存。

Vue3 Debug Hooks

Vue3 为我们提供了两个调试时的钩子:

  1. onRenderTracked
  2. onRenderTriggered

这两个事件都携带一个 DebuggerEvent 参数,以允许我们获悉是什么触发了 Vue 实例的重新渲染。

export default {
onRenderTriggered(e) {
debugger
// 检测什么依赖造成了组件的重新渲染
}
}

Reference

参考自 【译】Vue3生命周期钩子(hooks)完整指南